<template>
    <div>
      <video ref="localVideo" playsinline autoplay muted></video>
      <video ref="remoteVideo" playsinline autoplay></video>
      <div class="box">
        <el-button type = 'primary' @click="start" id="startButton" :disabled = 'vbutton.start'>Start</el-button>
        <el-button type = 'primary' @click="call" id="callButton" :disabled = 'vbutton.call'>Call</el-button>
        <el-button type = 'primary' @click="hangup" id="hangupButton" :disabled = 'vbutton.hangup'>Hang Up</el-button>
      </div>
    </div>
</template>

<script>
export default {
    name: 'ChatroomWebConnect',

    data() {
        return {
           vbutton:{
            start:false,
            call:true,
            hangup:true,
           },
           localVideo:'',
           remoteVideo:'', 
           startTime:null,
           localStream:null,
           pc1:null,
           pc2:null,
           offerOptions:{
            offerToReceiveAudio: 1,
            offerToReceiveVideo: 1
          },
        };
    },

    mounted() {
        this.init();
    },

    methods: {
        init(){
          this.localVideo = this.$refs['localVideo'];
          this.remoteVideo = this.$refs['remoteVideo'];
          this.localVideo.addEventListener('loadedmetadata', function() {
            console.log(`Local video videoWidth: ${this.videoWidth}px,  videoHeight: ${this.videoHeight}px`);
          });
          this.remoteVideo.addEventListener('loadedmetadata', function() {
            console.log(`Remote video videoWidth: ${this.videoWidth}px,  videoHeight: ${this.videoHeight}px`);
          });
          this.remoteVideo.addEventListener('resize', () => {
          console.log(`Remote video size changed to ${this.remoteVideo.videoWidth}x${this.remoteVideo.videoHeight} - Time since pageload ${performance.now().toFixed(0)}ms`);
          // We'll use the first onsize callback as an indication that video has started
          // playing out.
          if (this.startTime) {
            const elapsedTime = window.performance.now() - this.startTime;
            console.log('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
            this.startTime = null;
          }
        });
        },
        getName(pc) {
          return (pc === this.pc1) ? 'pc1' : 'pc2';
        },
        getOtherPc(pc) {
          return (pc === this.pc1) ? this.pc2 : this.pc1;
        },
        //点击开始按钮触发事件
        async start() {
          console.log('Requesting local stream');
          this.vbutton.start = true;
          try {
            const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
            console.log('Received local stream');
            this.localVideo.srcObject = stream;
            this.localStream = stream;
            this.vbutton.call = false;
          } catch (e) {
            alert(`getUserMedia() error: ${e.name}`);
          }
        },
        //点击拨打按钮触发事件
        async call() {
          this.vbutton.call = true;
          this.vbutton.hangup = false;
          console.log('Starting call');
          this.startTime = window.performance.now();
          const videoTracks = this.localStream.getVideoTracks();
          const audioTracks = this.localStream.getAudioTracks();
          if (videoTracks.length > 0) {
            console.log(`Using video device: ${videoTracks[0].label}`);
          }
          if (audioTracks.length > 0) {
            console.log(`Using audio device: ${audioTracks[0].label}`);
          }
          const configuration = {};
          console.log('RTCPeerConnection configuration:', configuration);
          this.pc1 = new RTCPeerConnection(configuration);
          console.log('Created local peer connection object pc1');
          this.pc1.addEventListener('icecandidate', e => this.onIceCandidate(this.pc1, e));
          this.pc2 = new RTCPeerConnection(configuration);
          console.log('Created remote peer connection object pc2');
          this.pc2.addEventListener('icecandidate', e => this.onIceCandidate(this.pc2, e));
          this.pc1.addEventListener('iceconnectionstatechange', e => this.onIceStateChange(this.pc1, e));
          this.pc2.addEventListener('iceconnectionstatechange', e => this.onIceStateChange(this.pc2, e));
          this.pc2.addEventListener('track', this.gotRemoteStream);

          this.localStream.getTracks().forEach(track => this.pc1.addTrack(track, this.localStream));
          console.log('Added local stream to pc1');

          try {
            console.log('pc1 createOffer start');
            const offer = await this.pc1.createOffer(this.offerOptions);
            await this.onCreateOfferSuccess(offer);
          } catch (e) {
            this.onCreateSessionDescriptionError(e);
          }
        },
        //拨打按钮中的一些方法
         onCreateSessionDescriptionError(error) {
          console.log(`Failed to create session description: ${error.toString()}`);
        },
        //更新pc1,pc2,并且初始化应答
        //*当pc1成功请求之后，我们更新客户端中本地和远程的描述。我不确定这些描述包括什么，但是这些资料很重要。
        async onCreateOfferSuccess(desc) {
          console.log(`Offer from pc1\n${desc.sdp}`);
          console.log('pc1 setLocalDescription start');
          try {
            await this.pc1.setLocalDescription(desc);
            this.onSetLocalSuccess(this.pc1);
          } catch (e) {
            this.onSetSessionDescriptionError();
          }

          console.log('pc2 setRemoteDescription start');
          try {
            await this.pc2.setRemoteDescription(desc);
            this.onSetRemoteSuccess(this.pc2);
          } catch (e) {
            this.onSetSessionDescriptionError();
          }

          console.log('pc2 createAnswer start');
          // Since the 'remote' side has no media stream we need
          // to pass in the right constraints in order for it to
          // accept the incoming offer of audio and video.
          try {
            const answer = await this.pc2.createAnswer();
            await this.onCreateAnswerSuccess(answer);
          } catch (e) {
            this.onCreateSessionDescriptionError(e);
          }
        },
      //
      onSetLocalSuccess(pc) {
        console.log(`${this.getName(pc)} setLocalDescription complete`);
      },

      onSetRemoteSuccess(pc) {
        console.log(`${this.getName(pc)} setRemoteDescription complete`);
      },

      onSetSessionDescriptionError(error) {
        console.log(`Failed to set session description: ${error.toString()}`);
      },
      //激发建立第二个视频。
      gotRemoteStream(e) {
        if (this.remoteVideo.srcObject !== e.streams[0]) {
          this.remoteVideo.srcObject = e.streams[0];
          console.log('pc2 received remote stream');
        }
      },
      //结束连接。
      //当pc2成功回复后，我们开始建立另一轮描述，只不过这次顺序正好相反
      async onCreateAnswerSuccess(desc) {
        console.log(`Answer from pc2:\n${desc.sdp}`);
        console.log('pc2 setLocalDescription start');
        try {
          await this.pc2.setLocalDescription(desc);
          this.onSetLocalSuccess(this.pc2);
        } catch (e) {
          this.onSetSessionDescriptionError(e);
        }
        console.log('pc1 setRemoteDescription start');
        try {
          await this.pc1.setRemoteDescription(desc);
          this.onSetRemoteSuccess(this.pc1);
        } catch (e) {
          this.onSetSessionDescriptionError(e);
        }
      },
      //连接事件听众
      async onIceCandidate(pc, event) {
          try {
            await (this.getOtherPc(pc).addIceCandidate(event.candidate));
            this.onAddIceCandidateSuccess(pc);
          } catch (e) {
            this.onAddIceCandidateError(pc, e);
          }
          console.log(`${this.getName(pc)} ICE candidate:\n${event.candidate ? event.candidate.candidate : '(null)'}`);
        },

      onAddIceCandidateSuccess(pc) {
        console.log(`${this.getName(pc)} addIceCandidate success`);
      },

      onAddIceCandidateError(pc, error) {
        console.log(`${this.getName(pc)} failed to add ICE Candidate: ${error.toString()}`);
      },
    //打印故障信息
      onIceStateChange(pc, event) {
        if (pc) {
          console.log(`${this.getName(pc)} ICE state: ${pc.iceConnectionState}`);
          console.log('ICE state change event: ', event);
        }
      },
      hangup() {
        console.log('Ending call');
        this.pc1.close();
        this.pc2.close();
        this.pc1 = null;
        this.pc2 = null;
        this.vbutton.hangup = true;
        this.vbutton.call = false;
      }

    },
};
</script>

<style lang="scss" scoped>
button {
  margin: 0 20px 0 0;
  width: 83px;
}

button .hangupButton {
    margin: 0;
}

video {
  --width: 45%;
  width: var(--width);
  height: calc(var(--width) * 0.75);
  margin: 0 0 20px 0;
  vertical-align: top;
}

video .localVideo {
  margin: 0 20px 20px 0;
}

div.box {
  margin: 1em;
}

@media screen and (max-width: 400px) {
  button {
    width: 83px;
    margin: 0 11px 10px 0;
  }

  video {
    height: 90px;
    margin: 0 0 10px 0;
    width: calc(50% - 7px);
  }
  video#localVideo {
    margin: 0 10px 20px 0;
  }
  }
</style>